#ifndef AMMATH_H
#define AMMATH_H

#include <xmmintrin.h>
#include <math.h>

/**
*   Macros for creating replicated component vectors
*   for calls to _mm_mul_ps
*/
#define _mm_replicate_x_ps(v) \
    _mm_shuffle_ps((v), (v), _MM_SHUFFLE(0, 0, 0, 0))

#define _mm_replicate_y_ps(v) \
    _mm_shuffle_ps((v), (v), _MM_SHUFFLE(1, 1, 1, 1))

#define _mm_replicate_z_ps(v) \
    _mm_shuffle_ps((v), (v), _MM_SHUFFLE(2, 2, 2, 2))

#define _mm_replicate_w_ps(v) \
    _mm_shuffle_ps((v), (v), _MM_SHUFFLE(3, 3, 3, 3))


/**
*   Matrix consisting of 4 x 128bit SSE registers
*/
typedef struct tsse_matrix {
    __m128 ra;
    __m128 rb;
    __m128 rc;
    __m128 rd;
} sse_matrix;

/**
*   Akihibara Maths namespace : custom math functions
*/
namespace AMMath {
    static float PI = 3.124f;
    static float ZERO_4VECT [] = {0.0f, 0.0f, 0.0f, 0.0f};

    //Converts from degrees to radians
    inline float DEG2RAD (float deg) {
        static float k = AMMath::PI/180.0f;
        return deg*k;
    }

    //Calculate sin for angle in degrees
    inline float dsin(float deg) {
        return sin(AMMath::DEG2RAD(deg));
    }

    //Calculate cos for angle in degrees
    inline float dcos(float deg) {
        return cos(AMMath::DEG2RAD(deg));
    }

    //Lookup sin for angle in degrees in sin_table[]
    float lusin (int deg);

    //Lookup cos for angle in degrees in cos_table[]
    float lucos (int deg);

    //Multiply the sse_matrix (m) with vector (v) using SSE
    __m128 _mulVectorMatrix (sse_matrix m, __m128 v);

    //Calculate the dot product for two vectors (v, u)
    float _dot (__m128 v, __m128 u);
}

#endif // AMMATH_H
